﻿Imports System
Imports System.Collections.Specialized
Imports System.Configuration
Imports System.Data
Imports System.Data.Common
Imports System.Data.OleDb
Imports System.Data.SqlClient
Imports System.Globalization
Imports System.Runtime.InteropServices
Imports System.Transactions
Imports System.Workflow.Runtime

Namespace System.Workflow.Runtime.Hosting
    Friend NotInheritable Class DbResourceAllocator
        ' Methods
        Friend Sub New(ByVal runtime As WorkflowRuntime, ByVal parameters As NameValueCollection, ByVal connectionString As String)
            If String.IsNullOrEmpty(connectionString) Then
                If (Not parameters Is Nothing) Then
                    Dim str As String
                    For Each str In parameters.AllKeys
                        If (String.Compare("ConnectionString", str, StringComparison.OrdinalIgnoreCase) = 0) Then
                            connectionString = parameters.Item("ConnectionString")
                            Exit For
                        End If
                    Next
                End If
                If (String.IsNullOrEmpty(connectionString) AndAlso (Not runtime Is Nothing)) Then
                    Dim commonParameters As NameValueConfigurationCollection = runtime.CommonParameters
                    If (Not commonParameters Is Nothing) Then
                        Dim str2 As String
                        For Each str2 In commonParameters.AllKeys
                            If (String.Compare("ConnectionString", str2, StringComparison.OrdinalIgnoreCase) = 0) Then
                                connectionString = commonParameters.Item("ConnectionString").Value
                                Exit For
                            End If
                        Next
                    End If
                End If
                If String.IsNullOrEmpty(connectionString) Then
                    Throw New ArgumentNullException("ConnectionString", ExecutionStringManager.MissingConnectionString)
                End If
            End If
            Me.Init(connectionString)
        End Sub

        Friend Sub DetectSharedConnectionConflict(ByVal transactionService As WorkflowCommitWorkBatchService)
            Dim service As SharedConnectionWorkflowCommitWorkBatchService = [TryCast](transactionService,SharedConnectionWorkflowCommitWorkBatchService)
            If ((Not service Is Nothing) AndAlso (String.Compare(service.ConnectionString, Me.connString, StringComparison.Ordinal) <> 0)) Then
                Throw New ArgumentException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.SharedConnectionStringSpecificationConflict, New Object() { Me.connString, service.ConnectionString }))
            End If
        End Sub

        Private Shared Function GetConnectionInfo(ByVal txSvc As WorkflowCommitWorkBatchService, ByVal transaction As Transaction) As SharedConnectionInfo
            Dim connectionInfo As SharedConnectionInfo = Nothing
            Dim service As SharedConnectionWorkflowCommitWorkBatchService = [TryCast](txSvc,SharedConnectionWorkflowCommitWorkBatchService)
            If (Not service Is Nothing) Then
                connectionInfo = service.GetConnectionInfo(transaction)
                If (connectionInfo Is Nothing) Then
                    Throw New ArgumentException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.InvalidTransaction, New Object(0  - 1) {}))
                End If
            End If
            Return connectionInfo
        End Function

        Friend Function GetEnlistedConnection(ByVal txSvc As WorkflowCommitWorkBatchService, ByVal transaction As Transaction, <Out> ByRef isNewConnection As Boolean) As DbConnection
            Dim dBConnection As DbConnection
            Dim connectionInfo As SharedConnectionInfo = DbResourceAllocator.GetConnectionInfo(txSvc, transaction)
            If (Not connectionInfo Is Nothing) Then
                dBConnection = connectionInfo.DBConnection
                isNewConnection = False
                Return dBConnection
            End If
            dBConnection = Me.OpenNewConnection
            dBConnection.EnlistTransaction(transaction)
            isNewConnection = True
            Return dBConnection
        End Function

        Friend Shared Function GetLocalTransaction(ByVal txSvc As WorkflowCommitWorkBatchService, ByVal transaction As Transaction) As DbTransaction
            Dim dBTransaction As DbTransaction = Nothing
            Dim connectionInfo As SharedConnectionInfo = DbResourceAllocator.GetConnectionInfo(txSvc, transaction)
            If (Not connectionInfo Is Nothing) Then
                dBTransaction = connectionInfo.DBTransaction
            End If
            Return dBTransaction
        End Function

        Private Sub Init(ByVal connectionStr As String)
            Me.SetConnectionString(connectionStr)
            Try 
                [Using] Me.OpenNewConnection(False)
                End [Using]
            Catch exception As Exception
                Throw New ArgumentException(ExecutionStringManager.InvalidDbConnection, "connectionString", exception)
            End Try
            If (Me.localProvider = Provider.OleDB) Then
                Me.connString = (Me.connString & ";OLE DB Services=-4")
            End If
        End Sub

        Friend Function NewCommand() As DbCommand
            Return DbResourceAllocator.NewCommand(Me.OpenNewConnection)
        End Function

        Friend Shared Function NewCommand(ByVal dbConnection As DbConnection) As DbCommand
            Return DbResourceAllocator.NewCommand(Nothing, dbConnection, Nothing)
        End Function

        Friend Shared Function NewCommand(ByVal commandText As String, ByVal dbConnection As DbConnection, ByVal transaction As DbTransaction) As DbCommand
            Dim command As DbCommand = dbConnection.CreateCommand
            command.CommandText = commandText
            command.Transaction = transaction
            Return command
        End Function

        Friend Function NewDbParameter() As DbParameter
            Return Me.NewDbParameter(Nothing, Nothing)
        End Function

        Friend Function NewDbParameter(ByVal parameterName As String, ByVal type As DbType) As DbParameter
            If (Me.localProvider = Provider.SqlClient) Then
                If (type = DbType.Int64) Then
                    Return New SqlParameter(parameterName, SqlDbType.BigInt)
                End If
                Return New SqlParameter(parameterName, type)
            End If
            If (type = DbType.Int64) Then
                Return New OleDbParameter(parameterName, OleDbType.BigInt)
            End If
            Return New OleDbParameter(parameterName, type)
        End Function

        Friend Function NewDbParameter(ByVal parameterName As String, ByVal value As Object) As DbParameter
            If (Me.localProvider = Provider.SqlClient) Then
                Return New SqlParameter(parameterName, value)
            End If
            Return New OleDbParameter(parameterName, value)
        End Function

        Friend Function NewDbParameter(ByVal parameterName As String, ByVal type As DbType, ByVal direction As ParameterDirection) As DbParameter
            Dim parameter As DbParameter = Me.NewDbParameter(parameterName, type)
            parameter.Direction = direction
            Return parameter
        End Function

        Friend Function OpenNewConnection() As DbConnection
            Return Me.OpenNewConnection(True)
        End Function

        Friend Function OpenNewConnection(ByVal disallowEnlist As Boolean) As DbConnection
            Dim connection As DbConnection = Nothing
            Dim connString As String = Me.connString
            If disallowEnlist Then
                connString = (connString & ";Enlist=false")
            End If
            If (Me.localProvider = Provider.SqlClient) Then
                connection = New SqlConnection(connString)
            Else
                connection = New OleDbConnection(connString)
            End If
            connection.Open
            Return connection
        End Function

        Friend Function OpenNewConnectionNoEnlist() As DbConnection
            Return Me.OpenNewConnection(True)
        End Function

        Private Sub SetConnectionString(ByVal connectionString As String)
            If (String.IsNullOrEmpty(connectionString) OrElse String.IsNullOrEmpty(connectionString.Trim)) Then
                Throw New ArgumentNullException("connectionString", ExecutionStringManager.MissingConnectionString)
            End If
            If New DbConnectionStringBuilder() { _
                .ConnectionString = connectionString _
            }.ContainsKey("enlist") Then
                Throw New ArgumentException(ExecutionStringManager.InvalidEnlist)
            End If
            Me.connString = connectionString
            Me.localProvider = Provider.SqlClient
        End Sub


        ' Properties
        Friend ReadOnly Property ConnectionString As String
            Get
                Return Me.connString
            End Get
        End Property


        ' Fields
        Friend Const ConnectionStringToken As String = "ConnectionString"
        Private connString As String
        Private Const EnlistFalseToken As String = ";Enlist=false"
        Private localProvider As Provider
    End Class
End Namespace

